--- import Layout from '../../../../layouts/Layout.astro'; import ProductPriceSection from '../../../../components/ProductPriceSection.tsx'; import Breadcrumb from '../../../../components/Breadcrumb.astro'; import UspStrip from '../../../../components/UspStrip.astro'; import { getBrandBySlugFromDB, getModelsByBrand, getColorsByModel, getProductsByModelAndColor, getProductIdsOffersLastUpdated } from '../../../../lib/products'; const { slug, model: modelSlug, color: colorSlug } = Astro.params; // Resolve brand const dbBrand = await getBrandBySlugFromDB(slug!); if (!dbBrand) return Astro.redirect('/merken'); const brandName = dbBrand.name; // Resolve model const models = await getModelsByBrand(slug!); const modelInfo = models.find(m => m.slug === modelSlug); if (!modelInfo) return Astro.redirect(`/merken/${slug}`); const modelName = modelInfo.name; // Get all colors for swatch navigation const allColors = await getColorsByModel(slug!, modelName); const currentColor = allColors.find(c => c.slug === colorSlug); if (!currentColor) { // If color not found, redirect to model page return Astro.redirect(`/merken/${slug}/${modelSlug}`); } // Get products for this specific color const products = await getProductsByModelAndColor(slug!, modelName, colorSlug!); if (products.length === 0) return Astro.redirect(`/merken/${slug}/${modelSlug}`); // Use the most popular product as the "hero" const hero = products[0]; // Combine all offers from all products with this color const allOffers = products.flatMap(p => p.offers); const allSizes = [...new Set(products.flatMap(p => p.sizes))].sort((a, b) => parseFloat(a) - parseFloat(b)); const lowestPrice = Math.min(...products.map(p => p.lowestPrice)); const highestOriginal = Math.max(...products.map(p => p.originalPrice)); const shopCount = allOffers.filter(o => o.inStock).length; const discount = highestOriginal > lowestPrice ? Math.round(((highestOriginal - lowestPrice) / highestOriginal) * 100) : 0; const colorName = currentColor.name; const fullName = `${brandName} ${modelName} ${colorName}`; const title = `${fullName} kopen? Vergelijk ${shopCount} ${shopCount === 1 ? 'winkel' : 'winkels'} vanaf €${lowestPrice.toFixed(2).replace('.', ',')} | SneakerPicks`; const description = `${fullName} prijzen vergelijken bij ${shopCount} Nederlandse webshops. Laagste prijs: €${lowestPrice.toFixed(2).replace('.', ',')}. Vind de beste deal.`; const canonicalUrl = `https://sneakerpicks.nl/merken/${slug}/${modelSlug}/${colorSlug}`; const productIds = products.map(p => Number(p.id)); const offersLastUpdated = await getProductIdsOffersLastUpdated(productIds); const dateModifiedIso = (offersLastUpdated ?? new Date()).toISOString(); const priceValidUntilIso = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; const merchantReturnPolicy = { "@type": "MerchantReturnPolicy", applicableCountry: "NL", returnPolicyCategory: "https://schema.org/MerchantReturnFiniteReturnWindow", merchantReturnDays: 14, returnMethod: "https://schema.org/ReturnByMail", returnFees: "https://schema.org/FreeReturn", }; // JSON-LD Product schema const productLd = { "@context": "https://schema.org", "@type": "Product", "inLanguage": "nl-NL", "name": fullName, "description": description, "url": canonicalUrl, ...(hero.image ? { "image": hero.image } : {}), "brand": { "@type": "Brand", "name": brandName }, "dateModified": dateModifiedIso, "publisher": { "@type": "Organization", "name": "SneakerPicks", "url": "https://sneakerpicks.nl", "logo": { "@type": "ImageObject", "url": "https://sneakerpicks.nl/logo.svg" } }, "offers": { "@type": "AggregateOffer", "lowPrice": lowestPrice > 0 ? lowestPrice : undefined, "highPrice": allOffers.length > 0 ? Math.max(...allOffers.map(o => o.price)) : undefined, "priceCurrency": "EUR", "offerCount": shopCount || 1, "availability": shopCount > 0 ? "https://schema.org/InStock" : "https://schema.org/OutOfStock", "priceValidUntil": priceValidUntilIso, "hasMerchantReturnPolicy": merchantReturnPolicy, "offers": allOffers.filter(o => o.inStock).slice(0, 10).map(o => ({ "@type": "Offer", "price": o.price, "priceCurrency": "EUR", "availability": "https://schema.org/InStock", "url": o.url, "priceValidUntil": priceValidUntilIso, "hasMerchantReturnPolicy": merchantReturnPolicy, "seller": { "@type": "Organization", "name": o.shop }, })) } }; const breadcrumbLd = { "@context": "https://schema.org", "@type": "BreadcrumbList", "inLanguage": "nl-NL", "itemListElement": [ { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://sneakerpicks.nl/" }, { "@type": "ListItem", "position": 2, "name": "Merken", "item": "https://sneakerpicks.nl/merken" }, { "@type": "ListItem", "position": 3, "name": brandName, "item": `https://sneakerpicks.nl/merken/${slug}` }, { "@type": "ListItem", "position": 4, "name": modelName, "item": `https://sneakerpicks.nl/merken/${slug}/${modelSlug}` }, { "@type": "ListItem", "position": 5, "name": colorName, "item": canonicalUrl } ] }; const sneakerData = { item_id: hero.id, item_name: fullName, item_brand: brandName, price: lowestPrice, }; ---